package VectorApproach;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import Application.ReadFileGenerateor;
import Application.TrajSplit;
import MyLoader.MyLoader;
import XmlLoader.FGObjProcess;
import XmlLoader.FGObjectTrajectoryStructure;

class Rule {
	int[] rule = null;
	int frequency = 0;
	
	public Rule(int[] rule) {
		this.rule = rule;
		this.frequency = 1;
	}
	
	boolean isEqual(int[] target) {
		boolean isEqual = true;
		if(target.length != this.rule.length) {
			isEqual = false;
		}
		int index = 0;
		while(isEqual && index < this.rule.length) {
			if(this.rule[index] != target[index]) {
				isEqual = false;
			}
			index = index + 1;
		}
		return isEqual;
	}
	
	public void ACT001_addFrequency() {
		this.frequency = this.frequency + 1;
	}
}

class AssociationRule {
	HashMap<Integer, ArrayList<Rule>> hashSize_rule = new HashMap<Integer, ArrayList<Rule>>();
	
	public void ACT001_push(int size, int[] rule) {
		ArrayList<Rule> listTarget = this.hashSize_rule.get(size);
		if(listTarget == null) {  //first add this size of rule
			this.hashSize_rule.put(size, new ArrayList<Rule>());
			this.hashSize_rule.get(size).add(new Rule(rule));
		}
		else {
			boolean isGet = false;
			int index = 0;
			while(!isGet && index < listTarget.size()) {
				Rule getRule = listTarget.get(index);
				if(getRule.isEqual(rule)) {  //rule has eisted
					getRule.ACT001_addFrequency();
					isGet = true;
				}
				index = index + 1;
			}
			if(!isGet) {  //create new rule
				listTarget.add(new Rule(rule));
			}
		}
	}
	
	public void ACT002_show() {
		int indexSize = 1, indexRule = 0;
		while(this.hashSize_rule.containsKey(indexSize)) {
			ArrayList<Rule> listRule = this.hashSize_rule.get(indexSize);
			indexRule = 0;
			while(indexRule < listRule.size()) {
				int index = 0;
				while(index < listRule.get(indexRule).rule.length) {
					System.out.print(listRule.get(indexRule).rule[index] + "->");
					index = index + 1;
				}
				System.out.println(" : " + listRule.get(indexRule).frequency);
				indexRule = indexRule + 1;
			}
			indexSize = indexSize + 1;
		}
	}
	
	public void ACT003_sort() {
		int indexSize = 1;
		while(this.hashSize_rule.containsKey(indexSize)) {
			ArrayList<Rule> listRule = this.hashSize_rule.get(indexSize);
			int indexFirst = 0;
			while(indexFirst < listRule.size() - 1) {
				int indexSec = indexFirst + 1;
				while(indexSec < listRule.size()) {
					if(listRule.get(indexFirst).frequency < listRule.get(indexSec).frequency) {
						Rule temp = listRule.get(indexFirst);
						listRule.set(indexFirst, listRule.get(indexSec));
						listRule.set(indexSec, temp);
						
					}
					indexSec = indexSec + 1;
				}
				indexFirst = indexFirst + 1;
			}
			indexSize = indexSize + 1;
		}
		
	}
}

class TrajToClusterPath {
	protected ArrayList<int[]> trajid_to_segid_to_cluster = new ArrayList<int[]>();
	
	public void ACT001_insertEle(int trajId, int segId, int clusterId) {
		int index = 0;
		boolean isAdd = false;
		int[] addEle = {trajId, segId, clusterId};
		while(!isAdd && index < this.trajid_to_segid_to_cluster.size()) {
			if(trajId < this.trajid_to_segid_to_cluster.get(index)[0]) {
				this.trajid_to_segid_to_cluster.add(index, addEle);
				isAdd = true;
			}
			index = index + 1;
		}
		if(!isAdd) {
			this.trajid_to_segid_to_cluster.add(addEle);
		}
	}
	
	public ArrayList<int[]> GET001_trajid_to_segid_to_cluster() {
		return this.trajid_to_segid_to_cluster;
	}
}

public class ClusterLinkTree {
	
	protected ArrayList<VClusterBulk> listCluster = null;
	protected TrajToClusterPath trajToPath = null;
	protected AssociationRule assRule = null;
	
	public ClusterLinkTree() {
		this.listCluster = new ArrayList<VClusterBulk>();
		this.trajToPath = new TrajToClusterPath();
		this.assRule = new AssociationRule();
	}
	
	protected void __001_pushCluster(VClusterBulk cluster) {
		int index = 0;
		boolean isAdd = false;
		while(!isAdd && index < this.listCluster.size()) {
			if(cluster.listTraj.size() > this.listCluster.get(index).listTraj.size()) {
				this.listCluster.add(index, cluster);
				isAdd = true;
			}
			index = index + 1;
		}
		if(!isAdd) {
			this.listCluster.add(cluster);
		}
	}
	
	protected void __002_pushSegToCluster(int trajId, int segId, int clusterId) {
		this.trajToPath.ACT001_insertEle(trajId, segId, clusterId);
	}
	
	public void ACT001_loadCluster(ArrayList<TrajVector> listTrajV, String filePath) {
		ArrayList<VClusterBulk> listLoadResult = VClusterReader.loadFromFile(listTrajV, filePath);
		int index = 0;
		while(index < listLoadResult.size()) {
			this.__001_pushCluster(listLoadResult.get(index));
			index = index + 1;
		}
	}
	//QW3HDFN
	public void ACT002_buildPathAssociationRule(int[] listTargetClusterIndex) {
		//generate trajectory rule
		int indexC = 0;
		int size = 0;
		if(listTargetClusterIndex == null) {
			size = this.listCluster.size();
		}
		else {
			size = listTargetClusterIndex.length;
		}
		while(indexC < size) {
			VClusterBulk cluster = null;
			if(listTargetClusterIndex == null) {
				cluster = this.listCluster.get(indexC);
			}
			else {
				cluster = this.listCluster.get(listTargetClusterIndex[indexC]);
			}
			int indexTraj = 0;
			while(indexTraj < cluster.GET001_listTraj().size()) {
				TrajVector getTraj = cluster.GET001_listTraj().get(indexTraj);
				this.__002_pushSegToCluster(getTraj.GET001_trajID(), getTraj.GET002_trajSegID(), cluster.GET001_clusterID());
				indexTraj = indexTraj + 1;
			}
			indexC = indexC + 1;
		}
		//generate association rule
		int indexTraj = 0;
		ArrayList<int[]> listTraj =  this.trajToPath.GET001_trajid_to_segid_to_cluster();
		int[] rule = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
		int curTrajId = listTraj.get(0)[0], curSize = 0;
		while(indexTraj <listTraj.size()) {
			if(listTraj.get(indexTraj)[0] == curTrajId) {
				rule[listTraj.get(indexTraj)[1]] = listTraj.get(indexTraj)[2];
				curSize = curSize + 1;
			}
			else {
				int[] addRule = new int[curSize];
				int index = 0, indexCurAdd = 0;
				while(index < rule.length) {
					if(rule[index] != -1) {
						addRule[indexCurAdd] = rule[index];
						rule[index] = -1;
						indexCurAdd = indexCurAdd  + 1;
					}
					index = index + 1;
				}
				this.assRule.ACT001_push(addRule.length, addRule);
				curSize = 0;
				curTrajId = listTraj.get(indexTraj)[0];
				indexTraj = indexTraj - 1;
			}
			indexTraj = indexTraj + 1;
		}
		//sort according to frequency
		
	}
	
	public void ACT003_showResult() {
		int index = 0;
		while(index < this.trajToPath.GET001_trajid_to_segid_to_cluster().size()) {
			int[] getEle = this.trajToPath.GET001_trajid_to_segid_to_cluster().get(index);
			System.out.println(getEle[0] + " " + getEle[1] + " " + getEle[2]);
			index = index + 1;
		}
	}
	
	public void ACT004_showAssRule() {
		this.assRule.ACT002_show();
	}
	
	public void ACT005_resetId() {
		int index = 0;
		while(index < this.listCluster.size()) {
			this.listCluster.get(index).clusterID = index;
			index = index + 1;
		}
	}
	
	public void ACT006_sortAssRule() {
		this.assRule.ACT003_sort();
	}
	
	public ArrayList<VClusterBulk> GET001_listCluster(){
		return this.listCluster;
	}

	public static void main(String[] args) {
		//generate list trajectory index
		System.out.println("Generate trajectory index file");
		new ReadFileGenerateor().ACT001_genFile(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]));
										
		//load trajectory xml data
		System.out.println("Load trajectory xml file");
		FGObjProcess fgObj = new FGObjProcess(args[3]);
		List<String> list_objIndex = fgObj.ACT004_getStringList(args[0]);
		List<FGObjectTrajectoryStructure> listAll = new MyLoader().ACT001_getListOfObj(args[3], list_objIndex);
		
		//trajectory segmentation
		System.out.println("Trajectory segmentation");
		TrajSplit split = new TrajSplit(Integer.parseInt(args[8]));
		ArrayList<TrajVector> listTrajV = new ArrayList<TrajVector>();
		FGObjectTrajectoryStructure traj = null;
		int index = 0;
		while(index < listAll.size()) {
			traj = listAll.get(index);
			if(traj.GET002_nNumberOfPoint() > 2) {
				split.readPosition(traj);
				split.compress(split.Positions.get(0), split.Positions.get(split.Positions.size() - 1));
				int indexResult = 0;
				ArrayList<TrajVector> listResult = split.transfromVector(600000);
				while(indexResult < listResult.size()) {
					listTrajV.add(listResult.get(indexResult));
					indexResult = indexResult + 1;
				}
			}
			index = index + 1;
		}
		while(listAll.size() > 0) {
			listAll.remove(0);
		}
		
		//load cluster
				
		ClusterLinkTree tree = new ClusterLinkTree();
		/*
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\170\\0\\9769.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\170\\1\\6161.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\170\\2\\6538.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\170\\3\\5857.txt");
		*/
		
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\171\\0\\1200.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\171\\1\\3101.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\171\\2\\838.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\171\\3\\4030.txt");
		
		/*
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\183\\0\\4850.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\183\\1\\6510.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\183\\2\\3520.txt");
		tree.ACT001_loadCluster(listTrajV, "C:\\Users\\test\\Desktop\\183\\3\\7750.txt");
		*/
		
		tree.ACT005_resetId();
		
		tree.ACT002_buildPathAssociationRule(null);
		//tree.ACT003_showResult();
		tree.ACT006_sortAssRule();
		tree.ACT004_showAssRule();
		
		tree.GET001_listCluster().get(5).ACT003_spliteByDistribution(10, 10, 720, 480);
		tree.GET001_listCluster().get(5).ACT010_countBoundary(null, Color.green);
	}
}
